home *** CD-ROM | disk | FTP | other *** search
/ Network Supervisor's Toolkit / Network Supervisor's Toolkit.iso / btrieve / breset / btc.cpp < prev    next >
C/C++ Source or Header  |  1996-07-10  |  32KB  |  877 lines

  1. /* ------------------------------  BTC.CPP  ------------------------------- */
  2.  
  3. /*
  4.    BTC V1.8 -  The C++ Class Library for Novell's Btrieve Record Manager 5.10
  5.    1/25/94 (C) 1994 John C. Leon.   All Rights Reserved.
  6.  
  7.    Written with and fully tested only under Borland C++ 3.1 and Btrieve for
  8.    DOS 5.10 ONLY, with all Btrieve patches available thru the date of this
  9.    file applied.
  10.  
  11.    NOTE:  Programs using this class library and its related functions
  12.       should #include "btc.hpp", and be linked with BTCS.LIB (small model)
  13.       or BTCL.LIB (large model).
  14.  
  15.       There is no need to include Novell's TURCBTRV.C file when using
  16.       BTC, as the universal Btrieve call is included in the BTC libraries,
  17.       and is declared in BTC.HPP.
  18.  
  19.    COMPILATION NOTES: WORD ALIGNMENT MUST BE OFF!
  20.               "TREAT ENUMS AS INT" MUST BE CHECKED!
  21.  
  22. */
  23.  
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27.  
  28. extern "C" { int BTRV(int, void*, void*, int*, void*, int); }
  29.  
  30. /* Misc Types */
  31. /* ------------------------------------------------------------------------ */
  32. typedef unsigned char byte;
  33. enum boolean {false, true};
  34. typedef char FNameStr[80];              //79 + null pad for a Btrieve filename
  35.  
  36. /* Btrieve KEY ATTRIBUTES */
  37. /* ------------------------------------------------------------------------ */
  38. enum KEY_FLAGS  {
  39.    Duplicates   =   1,  Modifiable =   2,  Binary     =   4,  Null = 8,
  40.    Segmented    =  16,  AltCol     =  32,  Descending =  64,
  41.    Supplemental = 128,  ExtType    = 256,  Manual     = 512
  42. };
  43.  
  44. /* Btrieve KEY TYPES */
  45. /* ------------------------------------------------------------------------ */
  46. enum KEY_TYPES  {
  47.    BString = 0, BInteger, BFloat, BDate, BTime, BDecimal,
  48.    BMoney, BLogical, BNumeric, BBFloat, BLString, BZString,
  49.    BUnsBinary = 14, BAutoInc
  50. };
  51.  
  52. /* Btrieve FILE OPEN MODES */
  53. /* ------------------------------------------------------------------------ */
  54. enum OPEN_MODE  {
  55.    Exclusive = -4, Verify, ReadOnly, Accel, Normal
  56. };
  57.  
  58. /* Btrieve FILE FLAGS */
  59. /* ------------------------------------------------------------------------ */
  60. enum FILE_FLAGS  {
  61.    VarLength =  1, BlankTrunc,  PreAllocate =   4, DataComp =   8,
  62.    KeyOnly   = 16, Free10 = 64, Free20      = 128, Free30   = 192
  63. };
  64.  
  65. /* Btrieve OP CODES */
  66. /* ------------------------------------------------------------------------ */
  67. enum OP_CODE  {
  68.    BOpen,       BClose,      BInsert,      BUpdate,      BDelete,    BGetEqual,
  69.    BGetNext,    BGetPrev,    BGetGr,       BGetGrEq,     BGetLess,   BGetLessEq,
  70.    BGetFirst,   BGetLast,    BCreate,      BStat,        BExtend,    BSetDosDir,
  71.    BGetDosDir,  BBegTran,    BEndTran,     BAbortTran,   BGetPos,    BGetDirect,
  72.    BStepNext,   BStop,       BVersion,     BUnlock,      BReset,     BSetOwner,
  73.    BClearOwner, BCrSuppIdx,  BDropSuppIdx, BStepFirst,   BStepLast,  BStepPrev,
  74.    BGetNextExt, BGetPrevExt, BStepNextExt, BStepPrevExt, BInsertExt,
  75.    BGetKey = 50
  76. };
  77.  
  78. /* Owner-Name Related Types */
  79. /* ------------------------------------------------------------------------ */
  80. typedef char OwnerName[9];        //8 chars max plus null
  81. enum OwnerAccess {RQ, RO, RQENC, ROENC};
  82.  
  83. /* Selected Btrieve ERROR CODES */
  84. /* ------------------------------------------------------------------------ */
  85. typedef enum BTC_ERR_CODES  {
  86.    FileNotOpen      =  3,  DataBufferLength = 22,
  87.    InvalidKeyNumber =  6,  RejectCount      = 60,
  88.    DiffKeyNumber    =  7,  IncorrectDesc    = 62,
  89.    InvalidPosition  =  8,  FilterLimit      = 64,
  90.    EndofFile        =  9,  IncorrectFldOff  = 65,
  91.    FileNotFound     = 12,  LostPosition     = 82,
  92.    BtrieveNotLoaded = 20
  93. };
  94.  
  95. /* Btrieve EXTENDED OPS COMP CODES/BIAS */
  96. /* ------------------------------------------------------------------------ */
  97. const byte
  98.    Equal       = 1,   UseAltColl =  32,
  99.    GreaterThan = 2,   UseField   =  64,
  100.    LessThan    = 3,   UseNoCase  = 128,
  101.    NotEqual    = 4,
  102.    GrOrEqual   = 5,
  103.    LessOrEqual = 6;
  104.  
  105. /* Btrieve EXTENDED OPS LOGIC CONSTANTS */
  106. /* ------------------------------------------------------------------------ */
  107. const int  NoFilter = 0;
  108. const char LastTerm = 0, NextTermAnd = 1, NextTermOr = 2; //As chars, can't
  109.                               //make an enum.
  110.  
  111. /* Other BTC-specific Constants */
  112. /* ------------------------------------------------------------------------ */
  113. const int
  114.    NotRequired            =     0,  //Dummy for BTRV calls where int not req'd.
  115.    MaxFixedRecLength      =  4090,  //Btrieve limits fixed rec length for std
  116.    MaxKBufferLength       =   255,  //files to 4090.  Max key size is 255.
  117.    None = 0, Drop = 1, Retain = 2,  //These 3 used in CloneFile function.
  118.    MaxExtDBufferLength    = 32767,  //May be used in future for ext. calls.
  119.    MaxFileSpecLength      =   665,
  120.    MaxNumSegments         =    24,
  121.    KeySpecSize            =    16;
  122.  
  123. /* Other BTC-specific Variables */
  124. /* ------------------------------------------------------------------------ */
  125. int  BStatus        = 0,          //Global Btrieve status variable.
  126.      VarNotRequired = 0;          //Dummy parameter.
  127. byte VarPosBlk[128];              //Dummy used in ops that don't pass or
  128.                   //return a position block.
  129.  
  130. /* ------------------------------------------------------------------------ */
  131. /*                             BTC DATA TYPES                               */
  132. /* ------------------------------------------------------------------------ */
  133. /* ------------------------------------------------------------------------ */
  134.  
  135. /* Data types for TRecMgr class */
  136. /* ------------------------------------------------------------------------ */
  137. struct TBTVersion  {
  138.    int Number;
  139.    int Rev;
  140.    char Product;
  141. };
  142.  
  143. class TBTRecMgr  {
  144.    protected:
  145.       boolean  BtrieveLoaded;
  146.       TBTVersion Version;
  147.       char     VerString[10];
  148.    public:
  149.       TBTRecMgr();
  150.       char* GetVersion()  { return VerString; };
  151.       virtual int BT( OP_CODE OpCode, int Key = 0 );
  152.       virtual ~TBTRecMgr() { };
  153. };
  154.  
  155. /* Data types for BBase class */
  156. /* ------------------------------------------------------------------------ */
  157.  
  158. // TACS and TAltColSeq are for alternate collating sequences
  159.  
  160. //TACS is for the actual alternate collating sequence itself
  161. struct TACS  {
  162.    byte Header;            //Header always equals 0xAC
  163.    char Name[8];           //not DOS filename, but name embedded in file
  164.    byte Table[256];
  165. };
  166.  
  167. //TAltColSeq is the class
  168. class TAltColSeq  {
  169.    public:
  170.       TACS Spec;
  171.       TAltColSeq() { };
  172.       TAltColSeq(FNameStr SpecName);
  173.       virtual ~TAltColSeq() { };
  174. };
  175.  
  176. union TKeySpec  {         // Data type for a Btrieve key spec; 'sent' Keyspec
  177.    struct  {
  178.       int  KeyPos;
  179.       int  KeyLen;
  180.       int  KeyFlags;
  181.       byte NotUsed[4];    // Tho not used in a create call, these 4 bytes
  182.       byte ExtKeyType;    // return number of unique recs in key after a
  183.       byte NullValue;     // stat call.
  184.       byte Reserved[4];
  185.    } SKeySpec;
  186.    struct  {
  187.       int  Irrelevant[3];      //This struct gives ability, on return from a
  188.       unsigned long NumUnique; //stat call, to directly read the number of
  189.    } RKeySpec;                 //unique records for a key.
  190.    byte Entire[16];
  191. };
  192.  
  193. struct TKeyList  {
  194.    TKeySpec KeySpec;
  195.    TKeyList *Next;
  196. };
  197.  
  198. struct SFileSpec  {
  199.    unsigned int RecLen;
  200.    int  PageSize;
  201.    int  NumKeys;
  202.    unsigned int NumRecs[2];// an array of int, w/high int second
  203.    int  FileFlags;
  204.    byte Reserved[2];
  205.    int  PreAlloc;          //On return from stat, this area holds UnusedPgs.
  206.    TKeySpec KeyArray[24];  //Technically, the KeyArray and AltColSpec merely
  207.    TACS AltColSpec;        //allocate space in a buffer of this data type, as it is unknown
  208. };                         //it is unknown exactly how many key specs there
  209.                //will be, or whether there will be an alternate
  210.                //collating sequence.
  211.  
  212. struct RFileSpec  {
  213.    byte Irrelevant[14];
  214.    unsigned int UnusedPgs; //great after a stat call; corresponds to PreAlloc
  215. };                         //field in struct SFileSpec
  216.  
  217. union TFileSpec  {         //full definition of a Btrieve filespec
  218.    SFileSpec FileSpec;
  219.    RFileSpec ReturnFileSpec;
  220.    byte      Entire[MaxFileSpecLength];
  221. };
  222.  
  223. class CFileSpec  {         //Useful in programs that use the CreateFile fcn.
  224.    public:
  225.       TFileSpec *Specs;
  226.       TKeyList  *KeyList;
  227.       CFileSpec();
  228.       CFileSpec(unsigned int RecLen, int PageSize, int NumKeys,
  229.         TKeyList *AKeyList=NULL, int FileFlags=0, int PreAlloc=0);
  230.       ~CFileSpec();
  231. };
  232.  
  233.                        /* In base object, no buffer is allo-
  234.                       cated in constructor, and the
  235.                       BT function is nearly abstract.
  236.                       Create a descendant class by adding
  237.                       a data buffer/struct and key buffer,
  238.                       and you're all set.  You'll surely
  239.                       also override the constructor,
  240.                       destructor, and BT functions. */
  241. class BBase  {
  242.    protected:
  243.       byte PosBlk[128];
  244.    public:
  245.       TFileSpec Specs;
  246.       FNameStr BFileName;
  247.       int IsOpen;
  248.       int SpecLength;
  249.       long NumRecs;
  250.       int NumSegs;
  251.       boolean HasAltCol;
  252.       boolean IsVariableLength;
  253.       boolean HasOwner;
  254.       OwnerName Owner;
  255.       char AltColName[9];     //8 for largest name, 1 for null
  256.       int DBufferLen;
  257.       BBase() { };
  258.       BBase(FNameStr UserFileName, OPEN_MODE OpenMode=Normal, OwnerName owner="");
  259.       virtual int Open(OPEN_MODE OpenMode=Normal);
  260.       virtual int Close();
  261.       virtual int Stat();
  262.       virtual int BT(OP_CODE OpCode, int Key=0) { return 0; };
  263.       virtual ~BBase();
  264. };
  265.  
  266. /* Data types for BFile class */
  267. /* ------------------------------------------------------------------------ */
  268. class BFile: public BBase  {
  269.    public:
  270.       byte *DBuffer;
  271.       byte *KBuffer;
  272.       unsigned int DBufferSize;
  273.       BFile();
  274.       BFile(FNameStr UserFileName, OPEN_MODE OpenMode = Normal, OwnerName owner = "",
  275.         unsigned int dBufferSize = MaxFixedRecLength);
  276.       virtual int BT(OP_CODE OpCode, int Key = 0);
  277.       virtual int AddSuppIndex(TKeyList* KeyList, FNameStr AltColFile="");
  278.       virtual ~BFile();
  279.       BFile& operator++();             //Overload prefix operators to do step
  280.       BFile& operator++(int);          //next(++) and step previous (--).
  281.       BFile& operator--();             //Overload postfix operators to do
  282.       BFile& operator--(int);          //insert(++) and delete (--).
  283.       BFile& operator=(BFile& bfixed); //Overload assignment operator to
  284.                        //copy data buffer to destination.
  285.       //CloneFile() needs write access to *DBuffer and *KBuffer.
  286.       friend int CloneBTFile(FNameStr CurrentFile, FNameStr NewFile, int Option,
  287.                  OwnerName Owner);
  288. };
  289.  
  290.  
  291. /* ------------------------------------------------------------------------ */
  292. /*                           METHOD DEFINITIONS                             */
  293. /* ------------------------------------------------------------------------ */
  294. /* ------------------------------------------------------------------------ */
  295.  
  296. TBTRecMgr::TBTRecMgr()  {
  297.    int sizeVersion = sizeof(Version);
  298.    BtrieveLoaded =
  299.       (BTRV(BVersion, VarPosBlk, &Version, &sizeVersion, &VarNotRequired, 0)) ?
  300.        false : true;
  301.    sprintf(VerString,"%d.%d%c", Version.Number, Version.Rev, Version.Product);
  302. }
  303.  
  304.  
  305.    /* The following function will not handle reset of other workstations as
  306.       written, as no true key buffer is passed.   Will handle begin/end/abort
  307.       transaction, reset & stop.  Would also handle version op, but is handled
  308.       by constructor anyway! */
  309.  
  310. int TBTRecMgr::BT(OP_CODE OpCode, int Key)  {
  311.    return BTRV(OpCode, VarPosBlk, &VarNotRequired, &VarNotRequired,
  312.            &VarNotRequired, Key);
  313. }
  314.  
  315.  
  316. TAltColSeq::TAltColSeq(FNameStr SpecName)  {
  317.    FILE *AltColSequence;
  318.    AltColSequence = fopen(SpecName, "rb");
  319.    fread(&Spec, sizeof(Spec), 1, AltColSequence); //read in the alt col seq
  320.    fclose(AltColSequence);
  321. }
  322.  
  323.  
  324. CFileSpec::CFileSpec()  {
  325.    Specs = new TFileSpec;
  326.    memset(Specs->Entire, 0, sizeof(Specs->Entire)); //Very important!!
  327. }
  328.  
  329.  
  330. CFileSpec::CFileSpec(unsigned int RecLen, int PageSize, int NumKeys,
  331.              TKeyList *AKeyList, int FileFlags, int PreAlloc)  {
  332.    Specs = new TFileSpec;
  333.    memset(Specs->Entire, 0, sizeof(Specs->Entire)); //Very important!!
  334.    Specs->FileSpec.RecLen    =  RecLen;        //Assign basic Btrieve file
  335.    Specs->FileSpec.PageSize  =  PageSize;      //characteristics.
  336.    Specs->FileSpec.NumKeys   =  NumKeys;
  337.    Specs->FileSpec.FileFlags =  FileFlags;
  338.    Specs->FileSpec.PreAlloc  =  PreAlloc;
  339.    int Counter = 0;
  340.    TKeyList *Keys = KeyList = AKeyList;
  341.    if ( Keys )  {
  342.       do {
  343.      Specs->FileSpec.KeyArray[Counter].SKeySpec.KeyPos     =
  344.         Keys->KeySpec.SKeySpec.KeyPos;
  345.      Specs->FileSpec.KeyArray[Counter].SKeySpec.KeyLen     =
  346.         Keys->KeySpec.SKeySpec.KeyLen;
  347.      Specs->FileSpec.KeyArray[Counter].SKeySpec.KeyFlags   =
  348.         Keys->KeySpec.SKeySpec.KeyFlags;
  349.      Specs->FileSpec.KeyArray[Counter].SKeySpec.ExtKeyType =
  350.         Keys->KeySpec.SKeySpec.ExtKeyType;
  351.      Counter++;
  352.      Keys = Keys->Next;
  353.       }  while ( Keys );
  354.    }
  355. }
  356.  
  357.  
  358. CFileSpec::~CFileSpec()  {
  359.    delete Specs;                 //Dispose of file specs.
  360.    if ( KeyList )  {
  361.       TKeyList *x1, *x2;         //Dispose of linked list of key specs.
  362.       x1 = KeyList;
  363.       while ( x1->Next )  {
  364.       x2 = x1->Next;
  365.       delete x1;
  366.       x1 = x2;
  367.       }
  368.       delete x1;
  369.    }
  370. }
  371.  
  372.  
  373. BBase::BBase(FNameStr UserFileName, OPEN_MODE OpenMode, OwnerName owner)  {
  374.    memset(&Specs.Entire, 0, sizeof(Specs.Entire));
  375.    memset(PosBlk, 0, sizeof(PosBlk));
  376.    memset(Owner, 0, sizeof(Owner));
  377.    DBufferLen = 0;
  378.  
  379.                //FileBufLen is 16 for filespec + 384 for max key
  380.                //specs + 265 for an alternate collating sequence.
  381.    int FileBufLen = MaxFileSpecLength;
  382.    int KeyBufLen  = 384;              //Max of 24 keys * 16 bytes per key spec
  383.  
  384.    HasAltCol = false;      //initialize to false..reset as needed later
  385.    strcpy(AltColName, ""); //initialize to empty string..reset as needed later
  386.  
  387.    HasOwner = (strlen(owner) == 0) ? false : true;
  388.    strcpy(Owner, owner);
  389.  
  390.    //Now copy DOS filename into object, and assure it's null terminated.
  391.    strcpy(BFileName, UserFileName);
  392.  
  393.    //Open file in specified mode.
  394.    int Status = Open(OpenMode);
  395.    if ( !Status )  {                 //if Open call went ok, i.e. Status = 0
  396.       Status = BTRV(BStat, PosBlk, &Specs, &FileBufLen, &KeyBufLen, 0);
  397.       if ( !Status )  {              //if Stat call went OK...fill data members
  398.      /* Btrieve filespecs and key specs are now in the BBase object!
  399.         FileBufLen will have been changed to size of data buffer returned by
  400.         stat call.  Save that value now. */
  401.      SpecLength = FileBufLen;
  402.      NumRecs = Specs.FileSpec.NumRecs[0] +
  403.            Specs.FileSpec.NumRecs[1] * 65536;
  404.  
  405.      IsVariableLength = ( (Specs.FileSpec.FileFlags & VarLength) == VarLength ) ?
  406.                 true: false;
  407.  
  408.      //Count total number of key segments
  409.      NumSegs = Specs.FileSpec.NumKeys;  //Initialize to # of keys.  Will
  410.                         //increment as needed in next
  411.                         //section.
  412.  
  413.      int Counter = 1, Counter1 = 0;
  414.      while (Counter <= Specs.FileSpec.NumKeys)
  415.         do {
  416.            if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & Segmented)
  417.           == Segmented)  {
  418.           if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol)
  419.              == AltCol)  HasAltCol = true;
  420.           NumSegs++;
  421.           Counter1++;
  422.                }
  423.            else  {
  424.           if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol)
  425.              == AltCol)  HasAltCol = true;
  426.           Counter++;
  427.           Counter1++;
  428.            }
  429.             }  while ((Specs.FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags & Segmented)
  430.                   == Segmented);
  431.      if (HasAltCol)  {
  432.         int AltColNameOffset = 16 + (16 * NumSegs) + 1;
  433.         memcpy( AltColName, &Specs.Entire[AltColNameOffset], 8 );
  434.         AltColName[8] = '\0';
  435.          }
  436.          BStatus = 0;       //Stat call went OK.  Data members filled now.
  437.       }
  438.       else  {
  439.      BStatus = Status;  //Open succeeded but stat failed.  Put error code
  440.      Close();           //for bad stat in global var BStatus, close file.
  441.       }//if stat call ok
  442.  
  443.    }//if file opened ok
  444.    else
  445.       BStatus = Status;     //Assign error code for bad open to global var.
  446. } //end BBase::BBase
  447.  
  448.  
  449. int BBase::Open(OPEN_MODE Mode)  {
  450.    int OpenStatus;
  451.    if (HasOwner)  {
  452.       DBufferLen = strlen(Owner) + 1;
  453.       OpenStatus = BTRV(BOpen, PosBlk, Owner, &DBufferLen, BFileName, Mode);
  454.    }
  455.    else
  456.       OpenStatus = BTRV(BOpen, PosBlk, &VarNotRequired, &VarNotRequired, BFileName, Mode);
  457.    IsOpen = (OpenStatus == 0) ? 1 : 0;
  458.    return OpenStatus;
  459. }
  460.  
  461.  
  462. int BBase::Close()  {
  463.    if (IsOpen)  {
  464.       int CloseStatus =  BTRV(BClose, PosBlk, &VarNotRequired, &VarNotRequired,
  465.                               &VarNotRequired, NotRequired);
  466.       IsOpen = (CloseStatus == 0) ? 0 : 1;
  467.       return CloseStatus;
  468.    }
  469.    else
  470.       return 0;
  471. }
  472.  
  473.  
  474.                //File must be open for this call to succeed.
  475. int BBase:: Stat()  {
  476.    memset(&Specs.Entire, 0, sizeof(Specs.Entire));
  477.  
  478.                //FileBufLen is 16 for filespec + 384 for max key
  479.                //specs + 265 for an alternate collating sequence.
  480.    int FileBufLen = MaxFileSpecLength;
  481.    int KeyBufLen  = 384;              //Max of 24 keys * 16 bytes per key spec
  482.  
  483.    HasAltCol = false;      //initialize to false..reset as needed later
  484.    strcpy(AltColName, ""); //initialize to empty string..reset as needed later
  485.  
  486.    BStatus = BTRV(BStat, PosBlk, &Specs, &FileBufLen, &KeyBufLen, 0);
  487.    if ( !BStatus )  {             //if Stat call went OK...fill data members
  488.       /* Btrieve filespecs and key specs are now in the BBase object!
  489.      FileBufLen will have been changed to size of data buffer returned by
  490.      stat call.  Save that value now. */
  491.       SpecLength = FileBufLen;
  492.       NumRecs = Specs.FileSpec.NumRecs[0] +
  493.       Specs.FileSpec.NumRecs[1] * 65536;
  494.       IsVariableLength = ( (Specs.FileSpec.FileFlags & VarLength) == VarLength ) ? true: false;
  495.  
  496.       //Count total number of key segments
  497.       NumSegs = Specs.FileSpec.NumKeys;  //Initialize to # of keys.  Will
  498.                      //increment as needed in next
  499.                      //section.
  500.  
  501.       int Counter = 1, Counter1 = 0;
  502.       while (Counter <= Specs.FileSpec.NumKeys)
  503.      do {
  504.         if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & Segmented) == Segmented)  {
  505.            if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol) == AltCol)
  506.           HasAltCol = true;
  507.            NumSegs++;
  508.            Counter1++;
  509.         }
  510.         else  {
  511.            if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol) == AltCol)
  512.           HasAltCol = true;
  513.            Counter++;
  514.            Counter1++;
  515.         }
  516.      }  while ((Specs.FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags & Segmented)
  517.           == Segmented);
  518.       if (HasAltCol)  {
  519.      int AltColNameOffset = 16 + (16 * NumSegs) + 1;
  520.      memcpy( AltColName, &Specs.Entire[AltColNameOffset], 8 );
  521.      AltColName[8] = '\0';
  522.       }
  523.    }
  524.    return BStatus;
  525. }
  526.  
  527.  
  528. BBase::~BBase()  {
  529.    Close();
  530. }
  531.  
  532.  
  533. BFile::BFile()  {
  534.    DBuffer = 0;
  535.    KBuffer = 0;
  536. }
  537.  
  538.  
  539. BFile::BFile(FNameStr UserFileName, OPEN_MODE OpenMode, OwnerName owner,
  540.          unsigned int dBufferSize): BBase(UserFileName, OpenMode, owner)  {
  541.    DBufferSize = (dBufferSize == 0) ? MaxFixedRecLength : dBufferSize;
  542.    DBuffer = new byte [DBufferSize];
  543.    if ( DBuffer )  memset(DBuffer, 0, DBufferSize);
  544.    KBuffer = new byte [MaxKBufferLength];
  545.    if ( KBuffer )  memset(KBuffer, 0, MaxKBufferLength);
  546. }
  547.  
  548.  
  549. int BFile::BT(OP_CODE OpCode, int Key)  {
  550.    return BTRV(OpCode, PosBlk, DBuffer, &DBufferLen, KBuffer, Key);
  551. }
  552.  
  553.  
  554. int BFile::AddSuppIndex(TKeyList* KeyList, FNameStr AltColFile)  {
  555.    int NewSegmentCount = 1;
  556.    boolean SuppIdxHasAltCol;
  557.    TKeyList* AKeyList = KeyList;
  558.    while ( AKeyList->Next )  {      //Count # of segments to be in supp index.
  559.       NewSegmentCount++;
  560.       AKeyList = AKeyList->Next;
  561.    }
  562.    if ( (NewSegmentCount + NumSegs) > MaxNumSegments )
  563.       return 1;
  564.    AKeyList = KeyList;
  565.    int Offset = 0;
  566.    do {
  567.       if ( (AKeyList->KeySpec.SKeySpec.KeyFlags & AltCol) == AltCol )
  568.      SuppIdxHasAltCol = true;
  569.       memmove( DBuffer+Offset, AKeyList, KeySpecSize);
  570.       Offset += KeySpecSize;
  571.       AKeyList = AKeyList->Next;
  572.    }  while (AKeyList);
  573.    if ( KeyList )  {
  574.       TKeyList *x1, *x2;         //Dispose of linked list of key specs.
  575.       x1 = KeyList;
  576.       while ( x1->Next )  {
  577.          x2 = x1->Next;
  578.          delete x1;
  579.          x1 = x2;
  580.       }
  581.      delete x1;
  582.    }
  583.    DBufferLen = KeySpecSize * NewSegmentCount;
  584.    //If the supplemental index is to have an alternate collating sequence, get
  585.    //it in the data buffer, and add its size to DBufferLen parameter.
  586.    if ( strlen(AltColFile) && SuppIdxHasAltCol )  {
  587.       TAltColSeq *ACS = new TAltColSeq(AltColFile);
  588.       memcpy( DBuffer+(KeySpecSize*NewSegmentCount), &ACS->Spec, sizeof(ACS->Spec));
  589.       DBufferLen += sizeof(ACS->Spec);
  590.       delete ACS;
  591.    }
  592.    BStatus = BT(BCrSuppIdx);
  593.    return BStatus;
  594. }
  595.  
  596.  
  597. BFile::~BFile()  {
  598.    if (DBuffer != 0)  delete DBuffer;
  599.    if (KBuffer != 0)  delete KBuffer;
  600. }
  601.  
  602.  
  603. BFile& BFile::operator++()  {
  604.    DBufferLen = DBufferSize;
  605.    BT(BStepNext);
  606.    return *this;
  607. }
  608.  
  609.  
  610. BFile& BFile::operator++(int)  {
  611.    BT(BInsert); //uses default key (2nd parameter) of 0 as key for positioning
  612.    return *this;
  613. }
  614.  
  615.  
  616. BFile& BFile::operator--()  {
  617.    BT(BStepPrev);
  618.    return *this;
  619. }
  620.  
  621.  
  622. BFile& BFile::operator--(int)  {
  623.    BT(BDelete);
  624.    return *this;
  625. }
  626.  
  627.  
  628. BFile& BFile::operator=(BFile& bfile)  {
  629.    DBufferLen = bfile.DBufferLen;
  630.    memmove(DBuffer, &(*bfile.DBuffer), bfile.DBufferSize);
  631.    return *this;
  632. }
  633.  
  634.  
  635. /* ------------------------------------------------------------------------ */
  636. /*                          SPECIAL BTC FUNCTIONS                           */
  637. /* ------------------------------------------------------------------------ */
  638. /* ------------------------------------------------------------------------ */
  639.  
  640. /* CreateFile() */  //See CREATE1.CPP and CREATE2.CPP for examples of usage.
  641. /* ------------------------------------------------------------------------ */
  642. int CreateBTFile(FNameStr UserFileName, TFileSpec* UserFileSpec,
  643.                  FNameStr AltColFile="", OwnerName Owner="",
  644.                  OwnerAccess Access=RQ)  {
  645.  
  646.    //Count total # of key segments in UserFileSpec.
  647.    boolean HasAltCol = false;
  648.    int NumSegs = UserFileSpec->FileSpec.NumKeys;
  649.    int Counter = 1, Counter1 = 0;
  650.    while (Counter <= UserFileSpec->FileSpec.NumKeys)
  651.       do {
  652.      if ((UserFileSpec->FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags
  653.         & Segmented) == Segmented)  {
  654.         if ((UserFileSpec->FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags
  655.            & AltCol) == AltCol)  HasAltCol = true;
  656.         NumSegs++;
  657.         Counter1++;
  658.          }
  659.      else  {
  660.         if ((UserFileSpec->FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags
  661.            & AltCol) == AltCol)  HasAltCol = true;
  662.         Counter++;
  663.         Counter1++;
  664.          }
  665.       }
  666.       while ((UserFileSpec->FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags & Segmented)
  667.         == Segmented);
  668.  
  669.    UserFileSpec->FileSpec.Reserved[1] = 0x00;
  670.    UserFileSpec->FileSpec.Reserved[2] = 0x00;
  671.  
  672.    //If an ACS was specified, get it into the filespec.
  673.    int SpecLength = 16 + (NumSegs * 16);
  674.    if ( strlen(AltColFile) && HasAltCol )  {
  675.       TAltColSeq *AltColObj = new TAltColSeq(AltColFile);
  676.       memcpy( &UserFileSpec->Entire[SpecLength],
  677.           &AltColObj->Spec, sizeof(AltColObj->Spec) );
  678.       SpecLength += sizeof(AltColObj->Spec);
  679.       delete AltColObj;
  680.    }
  681.  
  682.    BStatus = BTRV(BCreate, VarPosBlk, UserFileSpec, &SpecLength, UserFileName, 0);
  683.  
  684.    int ownerLength = strlen(Owner);
  685.    if (ownerLength != 0)  {
  686.       BFile *NewFile = new BFile(UserFileName, Accel, "", 9);
  687.       if (!BStatus)  {
  688.      if (ownerLength > 8)  ownerLength = 8;
  689.      //As there is nothing but nulls in DBuffer and KBuffer, by virtue
  690.      //of the BFile constructor for object NewFile, no need to copy the
  691.      //trailing '\0' in the Owner string...it'll be there already.
  692.      memmove(NewFile->DBuffer, Owner, ownerLength);
  693.      memmove(NewFile->KBuffer, Owner, ownerLength);
  694.      //Let Btrieve's set owner op see a trailing null.
  695.      NewFile->DBufferLen = ++ownerLength;
  696.      BStatus = NewFile->BT(BSetOwner, Access);
  697.          //Next line superfluous w/new destructor for BBase
  698.          //NewFile->Close();
  699.      delete NewFile;
  700.       }
  701.    }
  702.    return BStatus;
  703. }
  704.  
  705. /* CloneBTFile() */  //Declared as friend to BFile class.
  706. /* ------------------------------------------------------------------------ */
  707.  
  708. //For simplicity, this function assumes the source file for the cloning op is
  709. //closed.  Calling this function when the file is open will cause the function
  710. //to fail, probably w/code 85, so programmers beware.  If the Btrieve status
  711. //on a bad open is returned by the constructor for CurrentBFile, the CloneFile
  712. //function will return that value.
  713.  
  714. //NOTE!!! This function goes beyond the capability of "BUTIL -CLONE" in that
  715. //        this function has flexible handling of supplemental indexes in the
  716. //clone file (drop, retain, or make them permanent).  In addition, if no
  717. //permanent indexes use an alternate collating sequence, but one or more
  718. //supplemental indexes DOES use one, the clone can retain the supplemental
  719. //indexes WITH the alternate collating sequence, duplicating the file
  720. //structure perfectly.  This is something that "BUTIL -CLONE" CANNOT HANDLE!!
  721.  
  722. int CloneBTFile(FNameStr CurrentFile, FNameStr NewFile, int Option=Retain,
  723.           OwnerName Owner="")  {
  724.    BBase *CurrentBFile = new BBase(CurrentFile, ReadOnly, Owner);
  725.    if (BStatus)  {
  726.       delete CurrentBFile;
  727.       return BStatus;
  728.    }
  729.    CurrentBFile->Specs.FileSpec.FileFlags &= 0xFD;  //clear PreAllocate bit
  730.    CurrentBFile->Specs.ReturnFileSpec.UnusedPgs = 0;
  731.    int NewSpecLength = CurrentBFile->SpecLength;
  732.    int NewNumKeys = CurrentBFile->Specs.FileSpec.NumKeys;
  733.  
  734.    boolean *SuppIdxList = new boolean[24];
  735.    boolean *SuppIdxHasAltCol = new boolean[24];
  736.    memset(SuppIdxList, false, 48);
  737.    memset(SuppIdxHasAltCol, false, 48);
  738.    boolean HasSuppIdx = false, permKeyHasAltCol = false;
  739.    int NumberSuppSegs = 0, NumberSuppIdx = 0, NewOffset = 16, Counter;
  740.    TKeySpec *SuppIdx = new TKeySpec[CurrentBFile->NumSegs];
  741.  
  742.    TFileSpec *NewFileSpec = new TFileSpec;
  743.    memset( NewFileSpec->Entire, 0, sizeof(*NewFileSpec) );
  744.    memcpy( NewFileSpec->Entire, &CurrentBFile->Specs, 16 );
  745.  
  746.  
  747.    /* In this section, determine if there are any supplemental indexes in the
  748.       source Btrieve file.  If so, set boolean indicator HasSuppIdx (which
  749.       has function-wide scope) to true.  For each key segment (0 to 23)
  750.       identified as supplemental, set a corresponding boolean in an array
  751.       (SuppIdxList[24]) to true.  Get a count of supplemental indexes
  752.       (NumberSuppIdx), and a count of the total number of supplemental index
  753.       segments (NumberSuppSegs).  Populate an array of keyspecs (SuppIdx[24])
  754.       with the specs for all supplemental index segments.*/
  755.  
  756.    for ( Counter=0; Counter < CurrentBFile->NumSegs; Counter++)  {
  757.       int KeyFlags = CurrentBFile->Specs.FileSpec.KeyArray[Counter].SKeySpec.KeyFlags;
  758.       if ( ((KeyFlags & AltCol) == AltCol) && ((KeyFlags & Supplemental) != Supplemental))
  759.      permKeyHasAltCol = true;
  760.       if ( (KeyFlags & Supplemental ) == Supplemental)  {
  761.        if ((KeyFlags & AltCol) == AltCol)
  762.           SuppIdxHasAltCol[NumberSuppSegs] = true;
  763.        HasSuppIdx = true;
  764.        SuppIdxList[Counter] = true;
  765.        //Next line sets one structure equal to another.
  766.        SuppIdx[NumberSuppSegs] = CurrentBFile->Specs.FileSpec.KeyArray[Counter];
  767.        //Zero supplemental bit.
  768.        SuppIdx[NumberSuppSegs].SKeySpec.KeyFlags &= 0xFF7F;
  769.        NumberSuppSegs++;    //increment count of supplemental segments
  770.        if ( (KeyFlags & Segmented) != Segmented)  NumberSuppIdx++;
  771.       }
  772.    }
  773.  
  774.    if ( ((Option==Drop) || (Option==Retain)) && HasSuppIdx )  {
  775.       int Counter1 = 0;
  776.       for (Counter=1; Counter <= CurrentBFile->Specs.FileSpec.NumKeys; Counter++)  {
  777.      if ( SuppIdxList[Counter1] ) NewNumKeys--;
  778.      do {
  779.         if ( !SuppIdxList[Counter1] )  {
  780.            NewFileSpec->FileSpec.KeyArray[Counter1] =
  781.           CurrentBFile->Specs.FileSpec.KeyArray[Counter1];
  782.            NewOffset += 16;
  783.             }
  784.         else
  785.            NewSpecLength -= 16;
  786.         Counter1++;
  787.          } while
  788.        ( (CurrentBFile->Specs.FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags
  789.               & Segmented) == Segmented );
  790.       }
  791.       NewFileSpec->FileSpec.NumKeys = NewNumKeys;
  792.       if ( CurrentBFile->HasAltCol )
  793.      memmove( &NewFileSpec->Entire[NewOffset],
  794.           &CurrentBFile->Specs.Entire[ 16 + (CurrentBFile->NumSegs * 16)], 265 );
  795.       //Next line executed if source file has supplemental indexes, and if
  796.       //option chosen was to either drop or retain them.
  797.       BStatus = BTRV(BCreate, VarPosBlk, &NewFileSpec->Entire, &NewSpecLength,
  798.              NewFile, 0);
  799.    }  //end if
  800.  
  801.    /* If retaining the supplemental indexes AS supplemental indexes, then at
  802.       this point we're ready to add them to the newly created file. */
  803.  
  804.    if ( (Option == Retain) && HasSuppIdx )  {
  805.       BFile *NewBFile = new BFile( NewFile, Accel, "", MaxFileSpecLength );
  806.       int Counter1 = 0, DBuffOffset = 0;
  807.       for ( Counter=1; Counter<=NumberSuppIdx; Counter++)  {
  808.      do {
  809.         memmove( NewBFile->DBuffer+DBuffOffset, &SuppIdx[Counter1], 16 );
  810.         DBuffOffset += 16;
  811.         Counter1++;
  812.          } while ( (SuppIdx[Counter1-1].SKeySpec.KeyFlags & Segmented) == Segmented );
  813.      NewBFile->DBufferLen = Counter1 * 16;
  814.      if (SuppIdxHasAltCol[Counter1-1] && (!permKeyHasAltCol))  {
  815.         memmove(NewBFile->DBuffer+DBuffOffset,
  816.            &(CurrentBFile->Specs.Entire[CurrentBFile->SpecLength-265]), 265);
  817.         NewBFile->DBufferLen += 265;
  818.          }
  819.      BStatus = NewBFile->BT(BCrSuppIdx);
  820.      memset( NewBFile->DBuffer, 0, MaxFileSpecLength );
  821.      DBuffOffset++;
  822.       }  //end for
  823.       //Next line superfluous w/new destructor for BBase.
  824.       //NewBFile->Close();
  825.       delete NewBFile;
  826.    } //end if
  827.  
  828.    /* WARNING!  If user program specified 'None' and there actually ARE one or
  829.       more supplemental indexes in the source file, they WILL be retained in the
  830.       target file, as permanent indexes!  This can be done intentionally if
  831.       desired. */
  832.    if (   (Option==None)  ||  ( (Option==Retain) && !HasSuppIdx ) ||
  833.       ( (Option==Drop) && !HasSuppIdx )   )
  834.       BStatus = BTRV(BCreate, VarPosBlk, &CurrentBFile->Specs,
  835.              &CurrentBFile->SpecLength, NewFile, 0);
  836.  
  837.    //Next line superfluous w/new destuctor for BBase
  838.    //CurrentBFile->Close();
  839.    delete NewFileSpec;   //Note NewFileSpec would not have been used if
  840.              //HandleSupps parameter to this function was 'None'
  841.    delete SuppIdx;
  842.    delete SuppIdxHasAltCol;
  843.    delete SuppIdxList;
  844.    delete CurrentBFile;
  845.    return BStatus;
  846. }
  847.  
  848. /* NewKeySpec() */
  849. /* ------------------------------------------------------------------------ */
  850. // NewKeySpec() below is frequently used together with CreateBTFile().  See
  851. // CREATE1.CPP and CREATE2.CPP.
  852.  
  853. TKeyList* NewKeySpec(int KPos, int KLen, int KFlags, byte EType,
  854.              TKeyList *NextKey = 0)  {
  855.    TKeyList *TheKeyList = new TKeyList;
  856.    memset(TheKeyList, 0, sizeof(*TheKeyList));
  857.    TheKeyList->KeySpec.SKeySpec.KeyPos     = KPos;
  858.    TheKeyList->KeySpec.SKeySpec.KeyLen     = KLen;
  859.    TheKeyList->KeySpec.SKeySpec.KeyFlags   = KFlags;
  860.    TheKeyList->KeySpec.SKeySpec.ExtKeyType = EType;
  861.    TheKeyList->Next = NextKey;
  862.    return TheKeyList;
  863. }
  864.  
  865.  
  866. /* BtrieveIsLoaded() */
  867. /* ------------------------------------------------------------------------ */
  868. int BtrieveIsLoaded()  {
  869.    TBTVersion V;
  870.    int sizeV = sizeof(V);
  871.    return ( (BTRV( BVersion, VarPosBlk, &V, &sizeV, &VarNotRequired, 0 ))
  872.            == BtrieveNotLoaded ) ? false : true;
  873. }
  874.  
  875.  
  876. //end BTC.CPP
  877.